open Card;;


type ref_hand = 
  | Royal_straight_flush
  | Straight_flush
  | Four_of_kind
  | Full_house
  | Flush
  | Straight
  | Three_of_a_kind
  | Double_pair
  | Pair
  | Hight_card ;;

type hand = ref_hand * (card list);;

let evaluate_hand card_list=
  let b,list_c =  royal_straight_flush card_list in
    if b then Royal_straight_flush, list_c
    else let b, list_c = straight_flush card_list in
      if b then Straight_flush, list_c
      else let b,list_c = four_of_a_kind card_list in
        if b then Four_of_kind,list_c 
	else let b,list_c = full_house card_list in
          if b then Full_house, list_c
	  else let b, list_c = flush card_list in
            if b then Flush, list_c
	    else let b, list_c =  straight card_list in
	      if b then Straight, list_c
	      else let b,list_c = three_of_a_kind card_list in 
		if b then  Three_of_a_kind, list_c
		else let b, list_c = double_pair card_list in
		  if b then Double_pair,list_c
		  else let b,list_c = pair card_list in
                    if b then Pair, list_c
		    else let b, list_c = hight_card  card_list in
		      Hight_card, list_c;;


let valuate_hand h1 =
  match h1 with
    | Royal_straight_flush -> 10
    | Straight_flush       -> 9
    | Four_of_kind         -> 8
    | Full_house           -> 7 
    | Flush                -> 6
    | Straight             -> 5
    | Three_of_a_kind      -> 4
    | Double_pair          -> 3
    | Pair                 -> 2
    | Hight_card           -> 1;; 

let compare_hands h1 h2 = 
  (*We must use two cards because it's the only way to be sure the hand is a low straight*)
  let test1  l = List.exists (same_value (As,Club))  l in
  let test2  l = List.exists (same_value (Two,Club)) l in
  let test l = (test1 l)&(test2 l ) in
    match h1,h2 with 
  | (h1,_),(h2,_) when h1 <> h2 -> (valuate_hand h1) - (valuate_hand h2)

      (*Compare two low straight*)
  | (Straight, c1), (h2, c2) when (test c1)&(test c2)       -> 0
  | (Straight, c2), (h1, c1) when (test c1)&(test c2)       -> 0 
  | (Straight_flush, c1), (h2, c2) when (test c1)&(test c2) -> 0
  | (Straight_flush, c2), (h1, c1) when (test c1)&(test c2) -> 0

      (*Comapre a low straight with a hight straight*)
  | (Straight, c1), (h2, c2) when test c1       ->  compare_card_list (List.tl c1) (List.tl c2) 
  | (Straight, c2), (h1, c1) when test c1       ->  compare_card_list (List.tl c1) (List.tl c2) 
  | (Straight_flush, c1), (h2, c2) when test c1 ->  compare_card_list (List.tl c1) (List.tl c2)
  | (Straight_flush, c2), (h1, c1) when test c1 ->  compare_card_list (List.tl c1) (List.tl c2)
      (*Comapre two similare hands*)
  | (_,cl1),(_,cl2) -> compare_card_list cl1 cl2;;



let create_hand  card_list =
  let type_ref_hand, ref_hand  = evaluate_hand card_list in
  let l = Common.remove_list_element_list ref_hand card_list in    
  let sl =  List.sort (compare_cards) l in
      type_ref_hand,(Common.cut_list 5 (List.append ref_hand sl));; 
   
let string_of_ref_hand = function
  | Royal_straight_flush -> "Royal straight flush"
  | Straight_flush       -> "Straight flush"
  | Four_of_kind         -> "Four of a kind"
  | Full_house           -> "Full house"
  | Flush                -> "Flush"
  | Straight             -> "Straight"
  | Three_of_a_kind      -> "Three of a kind"
  | Double_pair          -> "Double Pair"
  | Pair                 -> "Pair"
  | Hight_card           -> "Hight Card"
;;

let string_of_hand (ref_hand, card_list) =
  (string_of_ref_hand ref_hand)^" "^(string_of_card_list card_list);;
  
   

   

